# -*- coding: utf-8 -*-
from openerp.osv import fields, osv
import openerp.addons.decimal_precision as dp

class res_company(osv.Model):
    _inherit = "res.company"
    _columns = {
        'sale_note': fields.text(u'默认报价单备注', translate=True, help="默认的报价单备注。"),
    }

class sale_order(osv.osv):
    _name = "sale.order"
    _inherit = ['mail.thread', 'ir.needaction_mixin']
    _description = u"销售订单"
    
    def _get_default_section_id(self, cr, uid, context=None):
        """ 从context或者用户上取得销售团队 """
        section_id = self._resolve_section_id_from_context(cr, uid, context=context) or False
        if not section_id:
            section_id = self.pool.get('res.users').browse(cr, uid, uid, context).default_section_id.id or False
        return section_id

    def _resolve_section_id_from_context(self, cr, uid, context=None):
        """ 返回 context 里 section_id 键对应的销售团队 ID 值，当无法取得唯一值时返回 None
        """
        if context is None:
            context = {}
        if type(context.get('default_section_id')) in (int, long): # Jeff 判断类型是数值，即ID
            return context.get('default_section_id')
        if isinstance(context.get('default_section_id'), basestring): # Jeff 判断类型是字符串，则是团队名称
            section_ids = self.pool.get('crm.case.section').name_search(cr, uid, name=context['default_section_id'], context=context)
            if len(section_ids) == 1:
                return int(section_ids[0][0])
        return None

    def _amount_line_tax(self, cr, uid, line, context=None):
        ''' Jeff 干嘛写在这里，不是应该写在sale_order_line类里面么？'''
        val = 0.0
        for c in self.pool.get('account.tax').compute_all(cr, uid, line.tax_id, line.price_unit * (1-(line.discount or 0.0)/100.0), line.product_uom_qty, line.product_id, line.order_id.partner_id)['taxes']:
            val += c.get('amount', 0.0)
        return val

    def _amount_all_wrapper(self, cr, uid, ids, field_name, arg, context=None):
        """ Jeff 为什么这里包了一层呢，参数完全一样 """
        return self._amount_all(cr, uid, ids, field_name, arg, context=context)

    def _amount_all(self, cr, uid, ids, field_name, arg, context=None):
        cur_obj = self.pool.get('res.currency')
        res = {}
        for order in self.browse(cr, uid, ids, context=context):
            res[order.id] = {
                'amount_untaxed': 0.0,
                'amount_tax': 0.0,
                'amount_total': 0.0,
            }
            val = val1 = 0.0
            cur = order.pricelist_id.currency_id
            for line in order.order_line:
                val1 += line.price_subtotal
                val += self._amount_line_tax(cr, uid, line, context=context)
            res[order.id]['amount_tax'] = cur_obj.round(cr, uid, cur, val)
            res[order.id]['amount_untaxed'] = cur_obj.round(cr, uid, cur, val1)
            res[order.id]['amount_total'] = res[order.id]['amount_untaxed'] + res[order.id]['amount_tax']
        return res

    def _invoiced_rate(self, cursor, user, ids, name, arg, context=None):
        ''' 与订单相关的发票，统计其中不等于草稿和取消的发票金额合计 '''
        res = {}
        for sale in self.browse(cursor, user, ids, context=context):
            if sale.invoiced:
                res[sale.id] = 100.0
                continue
            tot = 0.0
            for invoice in sale.invoice_ids:
                if invoice.state not in ('draft', 'cancel'):
                    tot += invoice.amount_untaxed
            if tot:
                res[sale.id] = min(100.0, tot * 100.0 / (sale.amount_untaxed or 1.00))
            else:
                res[sale.id] = 0.0
        return res

    def _invoiced(self, cursor, user, ids, name, arg, context=None):
        ''' 订单相关的所有发票都是已付款状态 '''
        res = {}
        for sale in self.browse(cursor, user, ids, context=context):
            res[sale.id] = True
            invoice_existence = False
            for invoice in sale.invoice_ids:
                if invoice.state!='cancel':
                    invoice_existence = True
                    if invoice.state != 'paid':
                        res[sale.id] = False
                        break
            if not invoice_existence or sale.state == 'manual':# Jeff 待开票状态这里就总返回 False，因为发票还没开完
                res[sale.id] = False
        return res
    
    def _invoice_exists(self, cursor, user, ids, name, arg, context=None):
        ''' Jeff 有发票存在，cancel的也算 '''
        res = {}
        for sale in self.browse(cursor, user, ids, context=context):
            res[sale.id] = False
            if sale.invoice_ids:
                res[sale.id] = True
        return res

    def _invoiced_search(self, cursor, user, obj, name, args, context=None):
        ''' 在搜索视图中查找已开票或未开票的销售订单 '''
        if not len(args):
            return []
        clause = ''
        sale_clause = ''
        no_invoiced = False
        for arg in args:
            if (arg[1] == '=' and arg[2]) or (arg[1] == '!=' and not arg[2]): # = True 或  != False
                clause += 'AND inv.state = \'paid\''
            else:
                clause += 'AND inv.state != \'cancel\' AND sale.state != \'cancel\'  AND inv.state <> \'paid\'  AND rel.order_id = sale.id '
                sale_clause = ',  sale_order AS sale '
                no_invoiced = True

        cursor.execute('SELECT rel.order_id ' \
                'FROM sale_order_invoice_rel AS rel, account_invoice AS inv '+ sale_clause + \
                'WHERE rel.invoice_id = inv.id ' + clause)
        res = cursor.fetchall()
        if no_invoiced:
            cursor.execute('SELECT sale.id ' \
                    'FROM sale_order AS sale ' \
                    'WHERE sale.id NOT IN ' \
                        '(SELECT rel.order_id ' \
                        'FROM sale_order_invoice_rel AS rel) and sale.state != \'cancel\'')
            res.extend(cursor.fetchall())
        if not res:
            return [('id', '=', 0)]
        return [('id', 'in', [x[0] for x in res])]

    def _get_order(self, cr, uid, ids, context=None):
        ''' Jeff 这么玩的好处是啥？ 直接列表推导式set去重不就行了么？ '''
        result = {}
        for line in self.pool.get('sale.order.line').browse(cr, uid, ids, context=context):
            result[line.order_id.id] = True
        return result.keys()

    _columns = {
        'name': fields.char('订单号', required=True, copy=False,
            readonly=True, states={'draft': [('readonly', False)], 'sent': [('readonly', False)]}, select=True),
        'origin': fields.char('源单据', help="生成此销售单的源单据."),
        'client_order_ref': fields.char('客户订单号', copy=False),
        'state': fields.selection([
            ('draft', '报价单'),
            ('sent', '已发送'),
            ('cancel', '已取消'),
            ('waiting_date', '排期'),         # jeff 在哪里用到的？
            ('progress', '销售订单'),
            ('manual', '待开票'),
            ('shipping_except', '发货异常'),
            ('invoice_except', '发票异常'),
            ('done', '完成'),
            ], '状态', readonly=True, copy=False, help="订单或报价单的状态。\
              \n异常状态是在发票被取消（发票异常）或发货单被取消（发货异常）时自动设置的 \
              .\n排期状态是发票已被确认但\
               等待计划在订单日运行.", select=True),
        'date_order': fields.datetime('日期', required=True, readonly=True, select=True, states={'draft': [('readonly', False)], 'sent': [('readonly', False)]}, copy=False),
        'create_date': fields.datetime('创建日期', readonly=True, select=True, help="订单被创建的日期."),   # Jeff 为什么要声明一下，不是自带的么，难道为了加索引？
        'date_confirm': fields.date('确认日期', readonly=True, select=True, help="销售订单确认的日期.", copy=False),
        'user_id': fields.many2one('res.users', '销售员', states={'draft': [('readonly', False)], 'sent': [('readonly', False)]}, select=True, track_visibility='onchange'),
        'partner_id': fields.many2one('res.partner', '客户', readonly=True, states={'draft': [('readonly', False)], 'sent': [('readonly', False)]}, required=True, change_default=True, select=True, track_visibility='always'),
        'partner_invoice_id': fields.many2one('res.partner', '发票地址', readonly=True, required=True, states={'draft': [('readonly', False)], 'sent': [('readonly', False)]}, help="当前销售订单的发票地址."),
        'partner_shipping_id': fields.many2one('res.partner', '发货地址', readonly=True, required=True, states={'draft': [('readonly', False)], 'sent': [('readonly', False)]}, help="当前订单的发货地址."),
        'order_policy': fields.selection([
                ('manual', '按需开票'),
            ], '结算方式', required=True, readonly=True, states={'draft': [('readonly', False)], 'sent': [('readonly', False)]},
            help="""此字段控制发票和发货的先后顺序."""),
        'pricelist_id': fields.many2one('product.pricelist', '价格表', required=True, readonly=True, states={'draft': [('readonly', False)], 'sent': [('readonly', False)]}, help="当前销售订单的价格表."),
        'currency_id': fields.related('pricelist_id', 'currency_id', type="many2one", relation="res.currency", string="货币", readonly=True, required=True),
        'project_id': fields.many2one('account.analytic.account', '协议', readonly=True, states={'draft': [('readonly', False)], 'sent': [('readonly', False)]}, help="订单相关的成本要素或协议"),
        'order_line': fields.one2many('sale.order.line', 'order_id', '销售订单行', readonly=True, states={'draft': [('readonly', False)], 'sent': [('readonly', False)]}, copy=True),
        'invoice_ids': fields.many2many('account.invoice', 'sale_order_invoice_rel', 'order_id', 'invoice_id', '发票', readonly=True, copy=False, help="这是此订单所生成的发票列表。一张订单可以生成多张发票（例如按行开票）"),
        'invoiced_rate': fields.function(_invoiced_rate, string='已开票百分比', type='float'),
        'invoiced': fields.function(_invoiced, string='已付款',
            fnct_search=_invoiced_search, type='boolean', help="标识订单的所有发票都已付款。"),
        'invoice_exists': fields.function(_invoice_exists, string='有发票',
            fnct_search=_invoiced_search, type='boolean', help="标识订单至少有一张发票."),
        'note': fields.text('订单备注'),
        'amount_untaxed': fields.function(_amount_all_wrapper, digits_compute=dp.get_precision('Account'), string='不含税金额合计',
            store={
                'sale.order': (lambda self, cr, uid, ids, c={}: ids, ['order_line'], 10),
                'sale.order.line': (_get_order, ['price_unit', 'tax_id', 'discount', 'product_uom_qty'], 10),
            },
            multi='sums', help="The amount without tax.", track_visibility='always'),
        'amount_tax': fields.function(_amount_all_wrapper, digits_compute=dp.get_precision('Account'), string='税额',
            store={
                'sale.order': (lambda self, cr, uid, ids, c={}: ids, ['order_line'], 10),
                'sale.order.line': (_get_order, ['price_unit', 'tax_id', 'discount', 'product_uom_qty'], 10),
            },
            multi='sums', help="The tax amount."),
        'amount_total': fields.function(_amount_all_wrapper, digits_compute=dp.get_precision('Account'), string='总计',
            store={
                'sale.order': (lambda self, cr, uid, ids, c={}: ids, ['order_line'], 10),
                'sale.order.line': (_get_order, ['price_unit', 'tax_id', 'discount', 'product_uom_qty'], 10),
            },
            multi='sums', help="The total amount."),
        'payment_term': fields.many2one('account.payment.term', '付款条件'),
        'fiscal_position': fields.many2one('account.fiscal.position', '替换规则'),
        'company_id': fields.many2one('res.company', '公司'),
        'section_id': fields.many2one('crm.case.section', '销售团队'),
        'procurement_group_id': fields.many2one('procurement.group', '补货组', copy=False),
        'product_id': fields.related('order_line', 'product_id', type='many2one', relation='product.product', string='产品'),
    }

    def _get_default_company(self, cr, uid, context=None):
        ''' Jeff 获取当前用户对应的公司 '''
        company_id = self.pool.get('res.users')._get_company(cr, uid, context=context)
        if not company_id:
            raise osv.except_osv(_('Error!'), _(u'当前用户没有默认的公司!'))
        return company_id

    def get_salenote(self, cr, uid, ids, partner_id, context=None):
        ''' Jeff 按客户的语言读取对应的默认订单备注 '''
        context_lang = context.copy() 
        if partner_id:
            partner_lang = self.pool.get('res.partner').browse(cr, uid, partner_id, context=context).lang
            context_lang.update({'lang': partner_lang})
        return self.pool.get('res.users').browse(cr, uid, uid, context=context_lang).company_id.sale_note

    def onchange_delivery_id(self, cr, uid, ids, company_id, partner_id, delivery_id, fiscal_position, context=None):
        ''' Jeff 收入或税替换规则是由收货地址决定的  '''
        r = {'value': {}}
        if not fiscal_position:
            if not company_id:
                company_id = self._get_default_company(cr, uid, context=context)
            fiscal_position = self.pool['account.fiscal.position'].get_fiscal_position(cr, uid, company_id, partner_id, delivery_id, context=context)
            if fiscal_position:
                r['value']['fiscal_position'] = fiscal_position
        return r
    def onchange_partner_id(self, cr, uid, ids, part, context=None):
        ''' Jeff 修改业务伙伴后带出其他字段值'''
        if not part:
            return {'value': {'partner_invoice_id': False, 'partner_shipping_id': False,  'payment_term': False, 'fiscal_position': False}}

        part = self.pool.get('res.partner').browse(cr, uid, part, context=context)
        addr = self.pool.get('res.partner').address_get(cr, uid, [part.id], ['delivery', 'invoice', 'contact'])
        pricelist = part.property_product_pricelist and part.property_product_pricelist.id or False
        payment_term = part.property_payment_term and part.property_payment_term.id or False
        dedicated_salesman = part.user_id and part.user_id.id or uid #Jeff 如果客户未指定销售员则为当前用户
        val = {
            'partner_invoice_id': addr['invoice'],
            'partner_shipping_id': addr['delivery'],
            'payment_term': payment_term,
            'user_id': dedicated_salesman,
        }
        delivery_onchange = self.onchange_delivery_id(cr, uid, ids, False, part.id, addr['delivery'], False,  context=context)
        val.update(delivery_onchange['value'])
        if pricelist:
            val['pricelist_id'] = pricelist
        sale_note = self.get_salenote(cr, uid, ids, part.id, context=context)
        if sale_note: val.update({'note': sale_note})  
        return {'value': val}

    def onchange_fiscal_position(self, cr, uid, ids, fiscal_position, order_lines, context=None):
        '''对定义了产品的订单行更新税

        :参数 list ids: 未使用
        :参数 int fiscal_position: 销售订单上的替换规则
        :参数 list order_lines: one2many写入的命令列表
        '''
        order_line = []
        fiscal_obj = self.pool.get('account.fiscal.position')
        product_obj = self.pool.get('product.product')
        line_obj = self.pool.get('sale.order.line')

        fpos = False
        if fiscal_position:
            fpos = fiscal_obj.browse(cr, uid, fiscal_position, context=context)
        
        for line in order_lines:
            # create    (0, 0,  { fields })
            # update    (1, ID, { fields })
            if line[0] in [0, 1]:
                prod = None
                if line[2].get('product_id'):
                    prod = product_obj.browse(cr, uid, line[2]['product_id'], context=context)
                elif line[1]:
                    prod =  line_obj.browse(cr, uid, line[1], context=context).product_id
                if prod and prod.taxes_id:
                    line[2]['tax_id'] = [[6, 0, fiscal_obj.map_tax(cr, uid, fpos, prod.taxes_id)]]
                order_line.append(line)

            # link      (4, ID)
            # link all  (6, 0, IDS)
            elif line[0] in [4, 6]:
                line_ids = line[0] == 4 and [line[1]] or line[2]
                for line_id in line_ids:
                    prod = line_obj.browse(cr, uid, line_id, context=context).product_id
                    if prod and prod.taxes_id:
                        order_line.append([1, line_id, {'tax_id': [[6, 0, fiscal_obj.map_tax(cr, uid, fpos, prod.taxes_id)]]}])
                    else:
                        order_line.append([4, line_id])
            else:
                order_line.append(line)
        return {'value': {'order_line': order_line}}
    def onchange_pricelist_id(self, cr, uid, ids, pricelist_id, order_lines, context=None):
        ''' Jeff 价格表修改后修改订单货币'''
        context = context or {}
        if not pricelist_id:
            return {}
        value = {
            'currency_id': self.pool.get('product.pricelist').browse(cr, uid, pricelist_id, context=context).currency_id.id
        }
        if not order_lines or order_lines == [(6, 0, [])]:
            return {'value': value}
        ''' Jeff 如果已有订单行，因为之前输入的价格是按之前价格表的货币输入的的，如5美元，如果改了价格表，可能是另一种货币（人民币）的价格表了，但系统不会自动帮你把订单行上的美元换成人民币 '''
        warning = {
            'title': _('Pricelist Warning!'),
            'message' : _('If you change the pricelist of this order (and eventually the currency), prices of existing order lines will not be updated.')
        }
        return {'warning': warning, 'value': value}

    _defaults = {
        'date_order': fields.datetime.now,
        'order_policy': 'manual',
        'company_id': _get_default_company,
        'state': 'draft',
        'user_id': lambda obj, cr, uid, context: uid,
        'name': lambda obj, cr, uid, context: '/',
        # Jeff 如果用户在客户界面点击【销售】并新建报价单则可在context里取到这些默认值 
        # Jeff 为什么partner_id没有设置个默认值？ 
        'partner_invoice_id': lambda self, cr, uid, context: context.get('partner_id', False) and self.pool.get('res.partner').address_get(cr, uid, [context['partner_id']], ['invoice'])['invoice'],
        'partner_shipping_id': lambda self, cr, uid, context: context.get('partner_id', False) and self.pool.get('res.partner').address_get(cr, uid, [context['partner_id']], ['delivery'])['delivery'],
        'note': lambda self, cr, uid, context: self.pool.get('res.users').browse(cr, uid, uid, context=context).company_id.sale_note,
        'section_id': lambda s, cr, uid, c: s._get_default_section_id(cr, uid, c),
    }

class sale_order_line(osv.osv):
    
    _name = 'sale.order.line'
    
    _description = '销售订单行'
    
    def _fnct_line_invoiced(self, cr, uid, ids, field_name, args, context=None):
        res = dict.fromkeys(ids, False)
        for this in self.browse(cr, uid, ids, context=context):
            # Jeff 开过发票 并且 发票没有都cancel
            res[this.id] = this.invoice_lines and \
                all(iline.invoice_id.state != 'cancel' for iline in this.invoice_lines)  
        return res
    
    def _order_lines_from_invoice(self, cr, uid, ids, context=None):
        ''' Jeff 当发票行变化的时候，根据发票行取到对应的订单行，注意这里命名不规范易造成混淆 '''
        # 直接读取多对多关联表是最直接的方式，也没绕过权限
        cr.execute("""SELECT DISTINCT sol.id FROM sale_order_invoice_rel rel JOIN
                                                  sale_order_line sol ON (sol.order_id = rel.order_id)
                                    WHERE rel.invoice_id = ANY(%s)""", (list(ids),))        # Jeff 这里的any用的牛啊，为啥不用 in ？
        return [i[0] for i in cr.fetchall()]

    def _amount_line(self, cr, uid, ids, field_name, arg, context=None):
        ''' 订单行金额小计，去掉折扣，加上税  '''
        tax_obj = self.pool.get('account.tax')
        cur_obj = self.pool.get('res.currency')
        res = {}
        if context is None:
            context = {}
        for line in self.browse(cr, uid, ids, context=context):
            # Jeff 由此可见折扣是一个在0到100之间的数字，并且是西方的折扣方式，比如 30 是 30% off
            price = line.price_unit * (1 - (line.discount or 0.0) / 100.0)
            taxes = tax_obj.compute_all(cr, uid, line.tax_id, price, line.product_uom_qty, line.product_id, line.order_id.partner_id)
            cur = line.order_id.pricelist_id.currency_id
            res[line.id] = cur_obj.round(cr, uid, cur, taxes['total'])
        return res

    _columns = {
        'order_id': fields.many2one('sale.order', '销售订单', required=True, ondelete='cascade', select=True, readonly=True, states={'draft':[('readonly',False)]}),
        'name': fields.text('说明', required=True, readonly=True, states={'draft': [('readonly', False)]}),
        'sequence': fields.integer('序号', help="当现实一批销售订单行时排序的依据."),
        'product_id': fields.many2one('product.product', '产品', domain=[('sale_ok', '=', True)], change_default=True, readonly=True, states={'draft': [('readonly', False)]}, ondelete='restrict'),
        'invoice_lines': fields.many2many('account.invoice.line', 'sale_order_line_invoice_rel', 'order_line_id', 'invoice_id', '发票行', readonly=True, copy=False),
        'invoiced': fields.function(_fnct_line_invoiced, string='已开票', type='boolean',   # Jeff 也就是说一个订单行不可以分开多次开票
            store={
                'account.invoice': (_order_lines_from_invoice, ['state'], 10),
                'sale.order.line': (lambda self,cr,uid,ids,ctx=None: ids, ['invoice_lines'], 10)
            }),
        'price_unit': fields.float('单价', required=True, digits_compute= dp.get_precision('Product Price'), readonly=True, states={'draft': [('readonly', False)]}),
        'price_subtotal': fields.function(_amount_line, string='小计', digits_compute= dp.get_precision('Account')),
        'tax_id': fields.many2many('account.tax', 'sale_order_tax', 'order_line_id', 'tax_id', '税', readonly=True, states={'draft': [('readonly', False)]}),
        'address_allotment_id': fields.many2one('res.partner', 'Allotment Partner',help="A partner to whom the particular product needs to be allotted."),   # Jeff 这个字段并没有对应的逻辑用到
        'product_uom_qty': fields.float('数量', digits_compute= dp.get_precision('Product UoS'), required=True, readonly=True, states={'draft': [('readonly', False)]}),
        'product_uom': fields.many2one('product.uom', '单位 ', required=True, readonly=True, states={'draft': [('readonly', False)]}),
        'product_uos_qty': fields.float('按销售单位计的数量' ,digits_compute= dp.get_precision('Product UoS'), readonly=True, states={'draft': [('readonly', False)]}),
        'product_uos': fields.many2one('product.uom', '销售单位'),
        'discount': fields.float('折扣 (%)', digits_compute= dp.get_precision('Discount'), readonly=True, states={'draft': [('readonly', False)]}),
        'th_weight': fields.float('重量', readonly=True, states={'draft': [('readonly', False)]}), # Jeff 这里输入净重还是毛重？
        'state': fields.selection(
                [('cancel', '已取消'),('draft', '草稿'),('confirmed', '已确认'),('exception', '异常'),('done', '已完成')],
                '状态', required=True, readonly=True, copy=False,
                help='* 对应的销售订单在草稿状态则订单行在\'草稿\' 状态。 \
                    \n*  对应的销售订单确认后，订单行在\'已确认\' 状态。\
                    \n* 对应的销售订单在异常状态时订单行在 \'异常\' 状态。 \
                    \n* 对应的销售订单已发货后订单行在 \'完成\' 状态。 \
                    \n* 对应的销售订单已取消则订单行在 \'已取消\' 状态。'),
        'order_partner_id': fields.related('order_id', 'partner_id', type='many2one', relation='res.partner', store=True, string='客户'),
        'salesman_id':fields.related('order_id', 'user_id', type='many2one', relation='res.users', store=True, string='销售员'),
        'company_id': fields.related('order_id', 'company_id', type='many2one', relation='res.company', string='公司', store=True, readonly=True),
        'delay': fields.float('交货提前期', required=True, help="从订单确认到发货给客户的天数", readonly=True, states={'draft': [('readonly', False)]}),
        'procurement_ids': fields.one2many('procurement.order', 'sale_line_id', '补货单'), # Jeff 这里的意义何在？难道一个orderline可以生成多个procurement？
        }

    def product_id_change(self, cr, uid, ids, pricelist, product, qty=0,
            uom=False, qty_uos=0, uos=False, name='', partner_id=False,
            lang=False, update_tax=True, date_order=False, packaging=False, fiscal_position=False, flag=False, context=None):
        ''' 根据订单和订单行上输入的数据，在输入产品后带出相关的字段：'''
        context = context or {}
        lang = lang or context.get('lang', False)   # Jeff 如客户没有指定语言，则使用当前用户的语言
        if not partner_id:
            raise osv.except_osv(_('No Customer Defined!'), _('Before choosing a product,\n select a customer in the sales form.'))
        warning = False
        product_uom_obj = self.pool.get('product.uom')
        partner_obj = self.pool.get('res.partner')
        product_obj = self.pool.get('product.product')
        context = {'lang': lang, 'partner_id': partner_id}
        partner = partner_obj.browse(cr, uid, partner_id)
        lang = partner.lang
        context_partner = {'lang': lang, 'partner_id': partner_id}   # Jeff这里的 lang 是个 browse_record吧，这也往context里放

        # Jeff 如果产品字段被清空（销售订单行里产品不是必输字段）
        if not product:
            return {'value': {'th_weight': 0,
                'product_uos_qty': qty}, 'domain': {'product_uom': [],
                   'product_uos': []}}
        # 若订单日期未输入，用当前日期作为取价格的条件
        if not date_order:
            date_order = time.strftime(DEFAULT_SERVER_DATE_FORMAT)

        result = {}
        warning_msgs = ''
        product_obj = product_obj.browse(cr, uid, product, context=context_partner)

        uom2 = False
        if uom:
            uom2 = product_uom_obj.browse(cr, uid, uom)
            if product_obj.uom_id.category_id.id != uom2.category_id.id:
                uom = False
        if uos:
            if product_obj.uos_id:
                uos2 = product_uom_obj.browse(cr, uid, uos)
                if product_obj.uos_id.category_id.id != uos2.category_id.id:
                    uos = False
            else:
                uos = False

        fpos = False
        if not fiscal_position:
            fpos = partner.property_account_position or False
        else:
            fpos = self.pool.get('account.fiscal.position').browse(cr, uid, fiscal_position)
        if update_tax: #The quantity only have changed
            result['tax_id'] = self.pool.get('account.fiscal.position').map_tax(cr, uid, fpos, product_obj.taxes_id)

        if not flag:
            result['name'] = self.pool.get('product.product').name_get(cr, uid, [product_obj.id], context=context_partner)[0][1]
            if product_obj.description_sale:
                result['name'] += '\n'+product_obj.description_sale
        domain = {}
        if (not uom) and (not uos):
            result['product_uom'] = product_obj.uom_id.id
            if product_obj.uos_id:
                result['product_uos'] = product_obj.uos_id.id
                result['product_uos_qty'] = qty * product_obj.uos_coeff
                uos_category_id = product_obj.uos_id.category_id.id
            else:
                result['product_uos'] = False
                result['product_uos_qty'] = qty
                uos_category_id = False
            result['th_weight'] = qty * product_obj.weight
            domain = {'product_uom':
                        [('category_id', '=', product_obj.uom_id.category_id.id)],
                        'product_uos':
                        [('category_id', '=', uos_category_id)]}
        elif uos and not uom: # only happens if uom is False
            result['product_uom'] = product_obj.uom_id and product_obj.uom_id.id
            result['product_uom_qty'] = qty_uos / product_obj.uos_coeff
            result['th_weight'] = result['product_uom_qty'] * product_obj.weight
        elif uom: # whether uos is set or not
            default_uom = product_obj.uom_id and product_obj.uom_id.id
            q = product_uom_obj._compute_qty(cr, uid, uom, qty, default_uom)
            if product_obj.uos_id:
                result['product_uos'] = product_obj.uos_id.id
                result['product_uos_qty'] = qty * product_obj.uos_coeff
            else:
                result['product_uos'] = False
                result['product_uos_qty'] = qty
            result['th_weight'] = q * product_obj.weight        # Round the quantity up

        if not uom2:
            uom2 = product_obj.uom_id
        # get unit price

        if not pricelist:
            warn_msg = _('You have to select a pricelist or a customer in the sales form !\n'
                    'Please set one before choosing a product.')
            warning_msgs += _("No Pricelist ! : ") + warn_msg +"\n\n"
        else:
            price = self.pool.get('product.pricelist').price_get(cr, uid, [pricelist],
                    product, qty or 1.0, partner_id, {
                        'uom': uom or result.get('product_uom'),
                        'date': date_order,
                        })[pricelist]
            if price is False:
                warn_msg = _("Cannot find a pricelist line matching this product and quantity.\n"
                        "You have to change either the product, the quantity or the pricelist.")

                warning_msgs += _("No valid pricelist line found ! :") + warn_msg +"\n\n"
            else:
                result.update({'price_unit': price})
        if warning_msgs:
            warning = {
                       'title': _('Configuration Error!'),
                       'message' : warning_msgs
                    }
        return {'value': result, 'domain': domain, 'warning': warning}

class procurement_order(osv.osv):
    _inherit = 'procurement.order'
    _columns = {
        'sale_line_id': fields.many2one('sale.order.line', string='销售订单行'),
    }

    def write(self, cr, uid, ids, vals, context=None):
        ''' Jeff 根据补货结果更新销售订单状态 '''
        if isinstance(ids, (int, long)):
            ids = [ids]
        res = super(procurement_order, self).write(cr, uid, ids, vals, context=context)
        from openerp import workflow           # Jeff 在这里写import不太好吧
        if vals.get('state') in ['done', 'cancel', 'exception']:
            for proc in self.browse(cr, uid, ids, context=context):
                if proc.sale_line_id and proc.sale_line_id.order_id:
                    order_id = proc.sale_line_id.order_id.id
                    if self.pool.get('sale.order').test_procurements_done(cr, uid, [order_id], context=context):
                        workflow.trg_validate(uid, 'sale.order', order_id, 'ship_end', cr)
                    if self.pool.get('sale.order').test_procurements_except(cr, uid, [order_id], context=context):
                        workflow.trg_validate(uid, 'sale.order', order_id, 'ship_except', cr)
        return res